#include "stdafx.h"
#include "simple_unit_test.h"
#include <iostream>
#include <string>
#include <vector>
#include <thread>

using namespace lfq;

const int COUNT_PER_THREAD = 10 * 1000 * 1000;
const int PRODUCER_THREAD_COUNT = 4;

const int CONSUMER_THREAD_COUNT = 1;

template <typename Allocator> struct PerfTestByAllocator
{
	typedef lockfree_queue<int, Allocator> queue_type;
	static queue_type ms_queue;

	static void test_perf(std::string head)
	{
		using namespace std;

		vector<thread> producer;
		vector<thread> consumer;

		for (int i = 0; i < CONSUMER_THREAD_COUNT; ++i)
		{
			consumer.push_back(thread(&consumerMain));
		}

		DWORD begin = ::GetTickCount();

		for (int i = 0; i < PRODUCER_THREAD_COUNT; ++i)
		{
			producer.push_back(thread(&producerMain));
		}

		for (size_t i = 0; i < producer.size(); ++i)
		{
			producer[i].join();
		}
		ms_queue.push(-1);		// end-of list

		for (size_t i = 0; i < consumer.size(); ++i)
		{
			consumer[i].join();
		}

		DWORD end = ::GetTickCount();

		cout << head << " Time: " << end - begin << " msec" << endl;
	}

	static void consumerMain()
	{
		bool isQuit = false;
		while (!isQuit)
		{
			queue_type::unsafe_list list;
			ms_queue.pop_all(list);

			for (auto it = list.begin(); it != list.end(); ++it)
			{
				if (*it == -1)
				{
					isQuit = true;
					break;
				}
			}
		}

		ms_queue.push(-1);
	}
	static void producerMain()
	{
		for (int i = 0; i < COUNT_PER_THREAD; ++i)
		{
			ms_queue.push(i);
		}
	}
};

template <typename Allocator> lockfree_queue<int, Allocator> PerfTestByAllocator<Allocator>::ms_queue;


TEST_F(basic_allocator)
{
	PerfTestByAllocator<allocator::entry_allocator_default<int>>::test_perf("default");
}

TEST_F(tls_allocator)
{
	PerfTestByAllocator<allocator::entry_allocator_tls_chunk<int>>::test_perf("tls");
}

TEST_F(tls_allocator_reuse)
{
	PerfTestByAllocator<allocator::entry_allocator_tls_chunk_reuse<int>>::test_perf("tls_reuse");
}

